package com.alibaba.citrus.ots.price.ability.functions.factory.price;

import com.alibaba.citrus.ots.common.annotation.FunctionInvoker;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.common.util.CheckUtils;
import com.alibaba.citrus.ots.common.util.MD5Utils;
import com.alibaba.citrus.ots.price.ability.functions.entity.price.PriceDimensionConfigEntity;
import com.alibaba.citrus.ots.price.ability.functions.entity.price.PriceDimensionRuleEntity;
import com.alibaba.citrus.ots.price.ability.functions.entity.price.PriceTypeEntity;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.otspricecenter.dto.request.DimensionProperty;
import com.epoch.app.otspricecenter.dto.request.DimensionPropertyInfoRequest;
import com.epoch.app.otspricecenter.dto.request.SyncPriceDimensionConfigDataRequest;
import com.epoch.app.otspricecenter.enums.DimensionPropertyEnum;
import com.epoch.app.otspricecenter.sdo.PriceDimensionConfigSDO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author: qiaojiange
 * @create: 2021/09/16
 * @Description 价格维度配置工厂
 */
public class PriceDimensionConfigFactory extends PriceBaseFactory {

    /**
     * 批量创建
     *
     * @param md5List
     * @param useDate
     * @return
     */
    private static List<PriceDimensionConfigEntity> batchCreate(List<String> md5List, Date useDate) {
        Result<List<PriceDimensionConfigSDO>> listResult = queryRepository.batchQueryDimensionConfig(md5List, useDate);

        List<PriceDimensionConfigEntity> dimensionConfigEntityList = new ArrayList<>();
        if (listResult.isSuccess() && CollectionUtils.isNotEmpty(listResult.getResult())) {
            listResult.getResult().forEach(e -> {
                dimensionConfigEntityList.add(PriceDimensionConfigEntity.of(e));
            });
        }
        return dimensionConfigEntityList;
    }

    /**
     * 创建维度配置实体映射表
     *
     * @param priceTypeEntity
     * @param request
     * @return key：价格数据记录 ID，value: PriceDimensionConfigEntity实体
     */
    public static Map<String, PriceDimensionConfigEntity> createDimensionConfigEntityMap(PriceTypeEntity priceTypeEntity, DimensionPropertyInfoRequest request) {
        HashMap<String, PriceDimensionConfigEntity> map = new HashMap<>();
        List<PriceDimensionConfigEntity> configEntityList = createPriceDimensionConfigEntityList(priceTypeEntity, request);
        if (CollectionUtils.isEmpty(configEntityList)) {
            return map;
        }
        return configEntityList.stream().collect(Collectors.toMap(PriceDimensionConfigEntity::obtainDimensionId, Function.identity()));
    }

    /**
     * 创建价格维度配置实体列表
     *
     * @param priceTypeEntity
     * @param request
     * @return
     */
    private static List<PriceDimensionConfigEntity> createPriceDimensionConfigEntityList(PriceTypeEntity priceTypeEntity, DimensionPropertyInfoRequest request) {
//        1、分割字符串获取所有的维度 id；
//        2、根据 维度ID，获取维度列表；
//        3、根据维度规则公式，和维度属性数据计算维度属性组字符串,根据字符串生成 MD5 摘要；；
//        4、根据 MD5 摘要获取价格维度数据（注意，这一步是批量获取的）；
        ArrayList<PriceDimensionConfigEntity> configEntities = new ArrayList<>();
        List<String> dimensionIds = priceTypeEntity.obtainDimensionSequence();
        List<PriceDimensionRuleEntity> ruleEntityList = PriceDimensionRuleFactory.batchCreate(dimensionIds);
        CheckUtils.check(CollectionUtils.isNotEmpty(ruleEntityList), "OTS-07-006-01-15-002", FacadeException.class, dimensionIds);
        List<String> md5List = new ArrayList<>();
        ruleEntityList.forEach(e -> {
            String md5 = e.calcMD5(request);
            md5List.add(md5);
        });
        List<PriceDimensionConfigEntity> priceDimensionConfigEntityList = PriceDimensionConfigFactory.batchCreate(md5List, request.getPriceUseDate());
//        当前一个时间点只可能获取一个价格数据
        Map<String, List<PriceDimensionConfigEntity>> dimensionIdMap = priceDimensionConfigEntityList.stream().collect(
                Collectors.groupingBy(PriceDimensionConfigEntity::obtainDimensionId));

        List<PriceDimensionConfigEntity> result = new ArrayList<>();
        dimensionIdMap.forEach((key, value) -> {
            //下面是兜底逻辑：
            //防止同一个维度中可能有维度配置数据，需要选取其中的一个维度中最近的时间进行筛选
            Collections.sort(value, (o1, o2) -> {
                return o2.obtainPriceStartDate().compareTo(o1.obtainPriceStartDate());
            });
            result.add(value.get(0));
        });
        return result;
    }


    /**
     * 创建PriceDimensionConfigEntity
     *
     * @param request 创建入参
     * @return PriceDimensionConfigEntity 配置实体
     */
    @FunctionInvoker(errorCode = "OTS-07-005-01-15-009",printLog = true)
    public static PriceDimensionConfigEntity create(SyncPriceDimensionConfigDataRequest request) {
        PriceDimensionConfigEntity entity = new PriceDimensionConfigEntity();
        PriceDimensionConfigSDO configSDO = PriceDimensionConfigSDO.builder().build();

        PriceDimensionRuleEntity priceDimensionRuleEntity = getDimensionRuleEntity(request, configSDO);
        String dimensionPropertiesGroup = priceDimensionRuleEntity.obtainDimensionPropertiesGroup(request,configSDO);
        configSDO.setDimensionId(priceDimensionRuleEntity.obtainDimensionId());
        configSDO.setDimensionPropertiesGroup(dimensionPropertiesGroup);
        //价格开始时间
        configSDO.setPriceStartDate(request.getPriceStartDate());
        //价格结束时间
        configSDO.setPriceEndDate(request.getPriceEndDate());
        //价格记录 id
        configSDO.setPriceRecordId(request.getPriceRecordId());
        //价格类型 id
        configSDO.setPriceTypeId(request.getPriceTypeId());
        //维度 id
        configSDO.setDimensionId(request.getDimensionId());
        //货品 id
        configSDO.setItemId(obtainItemId(request.getDimensionPropertyList()));

        //租户id
        configSDO.setTenantId(request.getTenantId());

        //生成的 md5值
        configSDO.setMd5Code(MD5Utils.encrypt32(configSDO.getDimensionPropertiesGroup()));
        entity.setPriceDimensionConfigSDO(configSDO);
        return entity;
    }

    private static String obtainItemId(List<DimensionProperty> dimensionPropertyList) {
        DimensionProperty dimensionProperty = dimensionPropertyList.stream().filter(
                e -> e.getDimensionName().equals(DimensionPropertyEnum.MATERIAL_CODE.getKey())).findFirst().get();
        return dimensionProperty == null ? "" : dimensionProperty.getDimensionValue();
    }

    /**
     * 获取维度规则实体
     *
     * @param request
     * @param configSDO
     * @return
     */
    @NotNull
    private static PriceDimensionRuleEntity getDimensionRuleEntity(SyncPriceDimensionConfigDataRequest request, PriceDimensionConfigSDO configSDO) {
        PriceDimensionRuleEntity priceDimensionRuleEntity = null;
        if (StringUtils.isNotBlank(request.getDimensionId())) {
            configSDO.setDimensionId(request.getDimensionId());
            //根据维度 id获取维度规则实体
            priceDimensionRuleEntity = PriceDimensionRuleFactory.create(request.getDimensionId());
        } else {
            //根据表名获取维度规则实体
            PriceDimensionRuleEntity ruleEntity = PriceDimensionRuleFactory.createByTableName(request.getTableName());
            if (StringUtils.isBlank(ruleEntity.obtainDimensionId())) {
                throw new FacadeException("根据表名:" + request + "获取维度数据失败！", request);
            }
            priceDimensionRuleEntity = ruleEntity;
        }
        return priceDimensionRuleEntity;
    }
}
